home *** CD-ROM | disk | FTP | other *** search
/ Programming Languages Suite / ProgramD2.iso / Borland / Borland C++ V5.02 / EXWRKSHP.PAK / FOOBTN.CPP next >
C/C++ Source or Header  |  1997-05-06  |  17KB  |  659 lines

  1. // Borland C++ - (C) Copyright 1991, 1992 by Borland International
  2. //
  3. //  Resource Workshop 32-bit Custom Control Example
  4.  
  5. // headers
  6. #include <windows.h>
  7. #include <windowsx.h>
  8. #include <custcntl.h>
  9.  
  10. #include <except.h>
  11.  
  12. #include <winsys\geometry.h>
  13.  
  14. #include "foobtn.h"
  15. #include "foobtn.rh"
  16.  
  17. // types
  18. enum ButtonState { bsUp, bsDown, bsFocused };
  19.  
  20. struct FooBtnData
  21. {
  22.  
  23.   ButtonState State;
  24.   bool Capture;
  25.   HFONT Font;
  26.  
  27. };
  28.  
  29. struct FooBtnStyleDlgData
  30. {
  31.  
  32.   HWND Parent;
  33.   CCSTYLEA *InitData;
  34.  
  35. };
  36.  
  37. // constants
  38. const char * const FooBtnClass = "FOOBTN";
  39. const int GWL_FOOBTNDATA = 0;
  40. const COLORREF LtGray = RGB( 192, 192, 192 );
  41. const COLORREF DkGray = RGB( 128, 128, 128 );
  42. const COLORREF Black = RGB( 0, 0, 0 );
  43.  
  44. static COLORREF Colors[4] =
  45.   {
  46.     RGB(255, 0, 0),   // Red
  47.     RGB(0, 255, 0),   // Green
  48.     RGB(0, 0, 255),   // Blue
  49.     RGB(255, 255, 0)  // Yellow
  50.   };
  51.  
  52. // globals
  53. HINSTANCE FBInstance;
  54.  
  55. // Function prototypes:
  56. //
  57. BOOL WINAPI            DllEntryPoint( HINSTANCE hInst, DWORD fdwReason, LPVOID lpvReserved );
  58. bool                   InitWindowClasses( HINSTANCE hInst );
  59.  
  60. extern "C"
  61. {
  62.   UINT CALLBACK __export CustomControlInfoA( LPCCINFOA acci );
  63.   BOOL CALLBACK __export FooBtnStyleA( HWND parent, LPCCSTYLEA pccs );
  64.   INT  CALLBACK __export FooBtnSizeToTextA( DWORD flStyle, DWORD flExtStyle, HFONT hFont, LPSTR pszText );
  65. }
  66.  
  67.  
  68. // Dialog procedure and message handlers for Control Style Dialog.
  69. //
  70. BOOL CALLBACK __export
  71. FooButtonStyleDlgProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam );
  72.  
  73. BOOL EvFBStyleInitDialog( HWND hwnd, HWND hwndFocus, LPARAM lParam );
  74. void EvFBStyleCommand( HWND hwnd, int id, HWND hwndCtl, UINT codeNotify );
  75.  
  76. static unsigned long StyleFromId( HWND parent, int baseCtrl, int numCtrls );
  77.  
  78.  
  79. // Window message handlers
  80. //
  81. LRESULT CALLBACK __export
  82. FooButtonWndProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam );
  83.  
  84. BOOL  EvFooBtnCreate( HWND hwnd, LPCREATESTRUCT lpCreateStruct );
  85. void  EvFooBtnDestroy( HWND hwnd );
  86. void  EvFooBtnLButtonDown( HWND hwnd, BOOL fDoubleClick, int x, int y, UINT keyFlags );
  87. void  EvFooBtnLButtonUp( HWND hwnd, int x, int y, UINT keyFlags );
  88. void  EvFooBtnMouseMove( HWND hwnd, int x, int y, UINT keyFlags );
  89. void  EvFooBtnSetFocus( HWND hwnd, HWND hwndOldFocus );
  90. void  EvFooBtnKillFocus( HWND hwnd, HWND hwndOldFocus );
  91. BOOL  EvFooBtnEraseBkgnd( HWND hwnd, HDC hdc );
  92. void  EvFooBtnPaint(HWND hwnd);
  93. void  EvFooBtnSetFont( HWND hwnd, HFONT hfont, BOOL fRedraw );
  94. HFONT EvFooBtnGetFont( HWND hwnd );
  95.  
  96.  
  97. // Inlines for retrieving state information about particular window instance.
  98. //
  99. inline FooBtnData *
  100. GetFooButtonData( HWND hwnd )
  101. {
  102.   return (FooBtnData *) GetWindowLong( hwnd, GWL_FOOBTNDATA );
  103. }
  104.  
  105.  
  106. // ----------------------------------------------------------------------------
  107. //
  108. //   Initialization
  109. //
  110. // ----------------------------------------------------------------------------
  111. BOOL WINAPI
  112. DllEntryPoint( HINSTANCE hInst, DWORD fdwReason, LPVOID /*lpvReserved*/ )
  113. {
  114.   bool result = true;
  115.  
  116.   switch( fdwReason )
  117.   {
  118.   case DLL_PROCESS_ATTACH:
  119.     FBInstance = hInst;
  120.     result = InitWindowClasses( hInst );
  121.     break;
  122.   }
  123.  
  124.   return result;
  125. }
  126.  
  127. bool
  128. InitWindowClasses( HINSTANCE hInst )
  129. {
  130.   WNDCLASS fooBtnClass;
  131.   bool result;
  132.  
  133.   // Use WinNT STATIC control class as a guideline...
  134.   //
  135.   GetClassInfo( 0, "STATIC", &fooBtnClass );
  136.  
  137.   fooBtnClass.style = CS_GLOBALCLASS | CS_PARENTDC;
  138.   fooBtnClass.lpfnWndProc = FooButtonWndProc;
  139.   fooBtnClass.cbClsExtra = 0;
  140.   fooBtnClass.cbWndExtra = 4;
  141.   fooBtnClass.hInstance = hInst;
  142.   fooBtnClass.hIcon = 0;
  143.   fooBtnClass.hbrBackground = 0;
  144.   fooBtnClass.lpszMenuName = 0;
  145.   fooBtnClass.lpszClassName = FooBtnClass;
  146.  
  147.   result = (RegisterClass( &fooBtnClass ) != 0) ? true : false;
  148.  
  149.   return result;
  150. }
  151.  
  152. // ----------------------------------------------------------------------------
  153. //
  154. //   Foo Button Custom Control Registration and Dialog Editor Support
  155. //
  156. // ----------------------------------------------------------------------------
  157.  
  158. CCINFOA FooBtnInfo =
  159.   {
  160.     { 'F', 'O', 'O', 'B', 'T', 'N', '\0' },
  161.                           // Class name for control
  162.     0,                    // CCF_ flags
  163.     { 'F', 'o', 'o', ' ', 'B', 'u', 't', 't', 'o', 'n', '\0' },
  164.                           // Short descriptive text
  165.     50, 14,               // Default width & height
  166.     FBS_FGYELLOW | FBS_BGBLUE | WS_CHILD | WS_VISIBLE | WS_TABSTOP,
  167.                           // Default style
  168.     0,
  169.                           // Default ex-style
  170.     0xF,                  // Control type mask, e.g. SS_TYPEMASK
  171.     { 'P', 'u', 's', 'h', ' ', 'M', 'e', '\0' },
  172.                           // Default text (CAPTION field?)
  173.     0,                    // Number of entries in style table
  174.     0,                    // Style table.
  175.     FooBtnStyleA,         // Style editing function - brings up edit style dialog.
  176.     FooBtnSizeToTextA,    // Size to Text function - allows control to size to caption.
  177.     0, 0                  // Two reserved DWORD fields.
  178.   };
  179.  
  180. //
  181. // Usage of CustomControlInfo() - call first w/ NULL to find out how many
  182. // controls are in the DLL, then call again w/ appropriately sized array
  183. // of CCINFO structs to retrieve the data.
  184. //
  185. UINT CALLBACK __export
  186. CustomControlInfoA( LPCCINFOA acci )
  187. {
  188.   if( acci )
  189.   {
  190.     memcpy( acci, &FooBtnInfo, sizeof( FooBtnInfo ) );
  191.   }
  192.  
  193.   return 1;
  194. }
  195.  
  196. BOOL CALLBACK __export
  197. FooBtnStyleA( HWND parent, LPCCSTYLEA pccs )
  198. {
  199.   bool result = false;
  200.  
  201.   if( pccs )
  202.   {
  203.     FooBtnStyleDlgData FBData;
  204.     FBData.Parent = parent;
  205.     FBData.InitData = pccs;
  206.  
  207.     result = DialogBoxParam( FBInstance, MAKEINTRESOURCE( IDD_EDITSTYLES ),
  208.                              parent, FooButtonStyleDlgProc, (LPARAM) &FBData
  209.                            );
  210.   }
  211.  
  212.   return result;
  213. }
  214.  
  215. INT CALLBACK __export
  216. FooBtnSizeToTextA( DWORD /*flStyle*/, DWORD /*flExtStyle*/, HFONT hFont, LPSTR pszText )
  217. {
  218.   // !PW Not implemented yet.
  219.   return -1;
  220. }
  221.  
  222. BOOL CALLBACK __export
  223. FooButtonStyleDlgProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
  224. {
  225.   switch( msg )
  226.   {
  227.     HANDLE_MSG( hwnd, WM_INITDIALOG, EvFBStyleInitDialog );
  228.     HANDLE_MSG( hwnd, WM_COMMAND, EvFBStyleCommand );
  229.   }
  230.  
  231.   return FALSE;
  232. }
  233.  
  234. BOOL
  235. EvFBStyleInitDialog( HWND hwnd, HWND /*hwndFocus*/, LPARAM lParam )
  236. {
  237.   bool result = true;
  238.   FooBtnStyleDlgData *FBData = (FooBtnStyleDlgData *) lParam;
  239.  
  240.   if( FBData && SetProp( hwnd, "FBData", (HANDLE) FBData ) )
  241.   {
  242.     // Center the dialog above the parent window.
  243.     //
  244.     TRect p, c;
  245.     TPoint r;
  246.  
  247.     GetWindowRect( FBData->Parent, &p );
  248.     GetWindowRect( hwnd, &c );
  249.  
  250.     r.x = p.left + (p.Width() - c.Width()) / 2;
  251.     r.y = p.top + (p.Height() - c.Height()) / 2;
  252.  
  253.     MoveWindow( hwnd, r.x, r.y, c.Width(), c.Height(), false );
  254.  
  255.     // Initialize the radio button controls
  256.     //
  257.     int id = ((FBData->InitData->flStyle & FBS_FTEXTMASK) >> FBS_FTEXTSHIFT) + IDC_FTEXTRED - 1;
  258.     HWND focusCtrl = GetDlgItem( hwnd, id );
  259.     Button_SetCheck( focusCtrl, true );
  260.  
  261.     id = ((FBData->InitData->flStyle & FBS_BTEXTMASK) >> FBS_BTEXTSHIFT) + IDC_BTEXTRED - 1;
  262.     Button_SetCheck( GetDlgItem( hwnd, id ), true );
  263.     SetFocus( focusCtrl );
  264.     result = false;
  265.   }
  266.   else
  267.   {
  268.     EndDialog( hwnd, false );
  269.   }
  270.  
  271.   return result;
  272. }
  273.  
  274. void
  275. EvFBStyleCommand( HWND hwnd, int id, HWND /*hwndCtl*/, UINT codeNotify )
  276. {
  277.   switch( id )
  278.   {
  279.  
  280.   case IDOK:
  281.     if( codeNotify == BN_CLICKED )
  282.     {
  283.       FooBtnStyleDlgData *FBData = (FooBtnStyleDlgData *) GetProp( hwnd, "FBData" );
  284.       if( FBData )
  285.       {
  286.         FBData->InitData->flStyle &= ~(FBS_FTEXTMASK | FBS_BTEXTMASK);
  287.         FBData->InitData->flStyle |= StyleFromId( hwnd, IDC_FTEXTRED, 4 );
  288.         FBData->InitData->flStyle |= StyleFromId( hwnd, IDC_BTEXTRED, 4 );
  289.       }
  290.  
  291.       RemoveProp( hwnd, "FBData" );
  292.       EndDialog( hwnd, TRUE );
  293.     }
  294.     break;
  295.  
  296.   case IDCANCEL:
  297.     if( codeNotify == BN_CLICKED )
  298.     {
  299.       RemoveProp( hwnd, "FBData" );
  300.       EndDialog( hwnd, FALSE );
  301.     }
  302.     break;
  303.  
  304.   }
  305. }
  306.  
  307. static unsigned long StyleFromId( HWND parent, int baseCtrl, int numCtrls )
  308. {
  309.   unsigned long style;
  310.   int ctrlId;
  311.  
  312.   for( ctrlId = baseCtrl; ctrlId <= baseCtrl+numCtrls; ctrlId++ )
  313.   {
  314.     if( Button_GetCheck( GetDlgItem( parent, ctrlId ) ) == BST_CHECKED )
  315.       break;
  316.   }
  317.  
  318.   if( ctrlId > baseCtrl+numCtrls )
  319.     ctrlId = baseCtrl;
  320.  
  321.    if( baseCtrl == IDC_FTEXTRED )
  322.      style = (ctrlId - IDC_FTEXTRED + 1) << FBS_FTEXTSHIFT;
  323.    else
  324.      style = (ctrlId - IDC_BTEXTRED + 1) << FBS_BTEXTSHIFT;
  325.  
  326.    return style;
  327. }
  328.  
  329. // ----------------------------------------------------------------------------
  330. //
  331. //   Foo Button Custom Control Implementation:
  332. //
  333. // ----------------------------------------------------------------------------
  334. //
  335. //   Window procedure and message handlers.
  336. //
  337. // ----------------------------------------------------------------------------
  338.  
  339. LRESULT CALLBACK __export
  340. FooButtonWndProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
  341. {
  342.   switch( msg )
  343.   {
  344.     HANDLE_MSG( hwnd, WM_CREATE, EvFooBtnCreate );
  345.     HANDLE_MSG( hwnd, WM_DESTROY, EvFooBtnDestroy );
  346.     HANDLE_MSG( hwnd, WM_LBUTTONDOWN, EvFooBtnLButtonDown );
  347.     HANDLE_MSG( hwnd, WM_LBUTTONUP, EvFooBtnLButtonUp );
  348.     HANDLE_MSG( hwnd, WM_MOUSEMOVE, EvFooBtnMouseMove );
  349.     HANDLE_MSG( hwnd, WM_SETFOCUS, EvFooBtnSetFocus );
  350.     HANDLE_MSG( hwnd, WM_KILLFOCUS, EvFooBtnKillFocus );
  351.     HANDLE_MSG( hwnd, WM_ERASEBKGND, EvFooBtnEraseBkgnd );
  352.     HANDLE_MSG( hwnd, WM_PAINT, EvFooBtnPaint );
  353.     HANDLE_MSG( hwnd, WM_SETFONT, EvFooBtnSetFont );
  354.     HANDLE_MSG( hwnd, WM_GETFONT, EvFooBtnGetFont );
  355.   }
  356.  
  357.   return DefWindowProc( hwnd, msg, wParam, lParam );
  358. }
  359.  
  360. BOOL EvFooBtnCreate( HWND hwnd, LPCREATESTRUCT /*lpCreateStruct*/ )
  361. {
  362.   bool result = false;
  363.   FooBtnData *fooData = (FooBtnData *) HeapAlloc( GetProcessHeap(), 0, sizeof( FooBtnData ) );
  364.  
  365.   if( fooData )
  366.   {
  367.     fooData->State = bsUp;
  368.     fooData->Capture = false;
  369.     fooData->Font = 0;
  370.  
  371.     SetWindowLong( hwnd, GWL_FOOBTNDATA, (LONG) fooData );
  372.     result = true;
  373.   }
  374.  
  375.   return result;
  376. }
  377.  
  378. void EvFooBtnDestroy( HWND hwnd )
  379. {
  380.   FooBtnData *fooData = GetFooButtonData( hwnd );
  381.  
  382.   if( fooData )
  383.   {
  384.     HeapFree( GetProcessHeap(), 0, fooData );
  385.     SetWindowLong( hwnd, GWL_FOOBTNDATA, 0L );
  386.   }
  387. }
  388.  
  389. void EvFooBtnLButtonDown( HWND hwnd, BOOL /*fDoubleClick*/, int /*x*/, int /*y*/, UINT /*keyFlags*/ )
  390. {
  391.   FooBtnData *fooData = GetFooButtonData( hwnd );
  392.  
  393.   if( fooData )
  394.   {
  395.     if( fooData->State == bsUp )
  396.     {
  397.       fooData->State = bsFocused;
  398.       SetFocus( hwnd );
  399.     }
  400.  
  401.     if( !fooData->Capture )
  402.     {
  403.       SetCapture( hwnd );
  404.       fooData->Capture = true;
  405.       fooData->State = bsDown;
  406.       InvalidateRect( hwnd, 0, FALSE );
  407.     }
  408.   }
  409. }
  410.  
  411. void EvFooBtnLButtonUp( HWND hwnd, int /*x*/, int /*y*/, UINT /*keyFlags*/ )
  412. {
  413.   FooBtnData *fooData = GetFooButtonData( hwnd );
  414.  
  415.   if( fooData && fooData->Capture )
  416.   {
  417.     fooData->Capture = false;
  418.     fooData->State = bsFocused;
  419.     ReleaseCapture();
  420.     InvalidateRect( hwnd, 0, FALSE );
  421.  
  422.     // Generate <Click> event here.
  423.   }
  424. }
  425.  
  426. void EvFooBtnMouseMove( HWND hwnd, int x, int y, UINT /*keyFlags*/ )
  427. {
  428.   FooBtnData *fooData = GetFooButtonData( hwnd );
  429.  
  430.   if( fooData && fooData->Capture )
  431.   {
  432.     TRect rect;
  433.     TPoint p( x, y );
  434.     ButtonState oldState;
  435.  
  436.     GetClientRect( hwnd, &rect );
  437.  
  438.     oldState = fooData->State;
  439.  
  440.     if( rect.Contains( p ) )
  441.       fooData->State = bsDown;
  442.     else
  443.       fooData->State = bsFocused;
  444.  
  445.     if( oldState != fooData->State )
  446.       InvalidateRect( hwnd, 0, FALSE );
  447.   }
  448. }
  449.  
  450. void EvFooBtnSetFocus( HWND hwnd, HWND /*hwndOldFocus*/ )
  451. {
  452.   FooBtnData *fooData = GetFooButtonData( hwnd );
  453.  
  454.   if( fooData && fooData->State != bsFocused )
  455.   {
  456.     fooData->State = bsFocused;
  457.     InvalidateRect( hwnd, 0, FALSE );
  458.   }
  459. }
  460.  
  461. void EvFooBtnKillFocus( HWND hwnd, HWND /*hwndOldFocus*/ )
  462. {
  463.   FooBtnData *fooData = GetFooButtonData( hwnd );
  464.  
  465.   if( fooData && fooData->State != bsUp )
  466.   {
  467.     fooData->State = bsUp;
  468.     InvalidateRect( hwnd, 0, FALSE );
  469.   }
  470. }
  471.  
  472. BOOL EvFooBtnEraseBkgnd( HWND /*hwnd*/, HDC /*hdc*/ )
  473. {
  474.   return TRUE;
  475. }
  476.  
  477. void EvFooBtnPaint( HWND hwnd )
  478. {
  479.   FooBtnData *fooData = GetFooButtonData( hwnd );
  480.  
  481.   if( fooData )
  482.   {
  483.     TRect fr, r, cr;
  484.     HBITMAP bitmap;
  485.     HPEN blackPen, whitePen, dkGrayPen, ltGrayPen, dkGrayDashPen;
  486.     HBRUSH nullBrush, ltGrayBrush;
  487.     HDC hdc, memdc;
  488.     PAINTSTRUCT ps;
  489.     int save;
  490.  
  491.     GetClientRect( hwnd, &cr );
  492.     r = fr = cr;
  493.  
  494.     nullBrush = GetStockBrush( NULL_BRUSH );
  495.     ltGrayBrush = GetStockBrush( LTGRAY_BRUSH );
  496.  
  497.     blackPen = GetStockPen( BLACK_PEN );
  498.     whitePen = GetStockPen( WHITE_PEN );
  499.     dkGrayPen = CreatePen( PS_SOLID, 1, DkGray );
  500.     ltGrayPen = CreatePen( PS_SOLID, 1, LtGray );
  501.     dkGrayDashPen = CreatePen( PS_DOT, 1, DkGray );
  502.  
  503.     hdc = BeginPaint( hwnd, &ps );
  504.     memdc = CreateCompatibleDC( hdc );
  505.     bitmap = CreateCompatibleBitmap( hdc, cr.right, cr.bottom );
  506.  
  507.     save = SaveDC( memdc );
  508.  
  509.     SelectBitmap( memdc, bitmap );
  510.     SelectPen( memdc, blackPen );
  511.     SelectBrush( memdc, nullBrush );
  512.  
  513.     Rectangle( memdc, r.left, r.top, r.right, r.bottom );
  514.     r.Inflate( -1, -1 );
  515.  
  516.     if( fooData->State != bsDown )
  517.     {
  518.       SelectPen( memdc, whitePen );
  519.       MoveToEx( memdc, r.left, r.bottom-2, 0 );
  520.       LineTo( memdc, r.left, r.top );
  521.       LineTo( memdc, r.right-1, r.top );
  522.       MoveToEx( memdc, r.right-3, r.top+1, 0 );
  523.       LineTo( memdc, r.left+1, r.top+1 );
  524.       LineTo( memdc, r.left+1, r.bottom-2 );
  525.  
  526.       SelectPen( memdc, dkGrayPen );
  527.       MoveToEx( memdc, r.left, r.bottom-1, 0 );
  528.       LineTo( memdc, r.right-1, r.bottom-1 );
  529.       LineTo( memdc, r.right-1, r.top-1 );
  530.       MoveToEx( memdc, r.right-2, r.top+1, 0 );
  531.       LineTo( memdc, r.right-2, r.bottom-2 );
  532.       LineTo( memdc, r.left, r.bottom-2 );
  533.  
  534.       r.Inflate( -2, -2 );
  535.     }
  536.     else
  537.     {
  538.       SelectPen( memdc, dkGrayPen );
  539.       MoveToEx( memdc, r.left, r.bottom-1, 0 );
  540.       LineTo( memdc, r.left, r.top );
  541.       LineTo( memdc, r.right, r.top );
  542.  
  543.       r.left++;
  544.       r.top++;
  545.     }
  546.  
  547.     SelectBrush( memdc, ltGrayBrush );
  548.     PatBlt( memdc, r.left, r.top, r.Width(), r.Height(), PATCOPY );
  549.  
  550.     if( fooData->State != bsDown )
  551.     {
  552.       fr.left += 4;
  553.       fr.top += 4;
  554.       fr.right -= 6;
  555.       fr.bottom -= 6;
  556.     }
  557.     else
  558.     {
  559.       fr.left += 6;
  560.       fr.top += 6;
  561.       fr.right -= 4;
  562.       fr.bottom -= 4;
  563.     }
  564.  
  565.     {
  566.       TRect tr;
  567.       char caption[64];
  568.       int len;
  569.  
  570.       if( fooData->Font )
  571.         SelectFont( memdc, fooData->Font );
  572.  
  573.       len  = GetWindowText( hwnd, caption, sizeof( caption )-1 );
  574.       caption[len] = 0;
  575.  
  576.       unsigned long style = GetWindowLong( hwnd, GWL_STYLE );
  577.       if( style & WS_DISABLED )
  578.       {
  579.         SetTextColor( memdc, DkGray );
  580.         SetBkColor( memdc, LtGray );
  581.       }
  582.       else
  583.       {
  584.         SetTextColor( memdc, Colors[ ((style & FBS_FTEXTMASK) >> FBS_FTEXTSHIFT) - 1 ] );
  585.  
  586.         COLORREF bkcolor = Colors[ ((style & FBS_BTEXTMASK) >> FBS_BTEXTSHIFT) - 1 ];
  587.         SetBkColor( memdc, bkcolor );
  588.  
  589.         HBRUSH bkbrush = CreateSolidBrush( bkcolor );
  590.         SelectBrush( memdc, bkbrush );
  591.         PatBlt( memdc, r.left, r.top, r.Width(), r.Height(), PATCOPY );
  592.         SelectBrush( memdc, nullBrush );
  593.         DeleteObject( bkbrush );
  594.       }
  595.  
  596.       tr.SetNull();
  597.       DrawText( memdc, caption, -1, &tr, DT_CALCRECT | DT_SINGLELINE );
  598.  
  599.       if( tr.Width() < fr.Width() )
  600.       {
  601.         fr.left += (fr.Width() - tr.Width()) / 2;
  602.         fr.right = fr.left + tr.Width();
  603.       }
  604.  
  605.       if( tr.Height() < fr.Height() )
  606.       {
  607.         fr.top += (fr.Height() - tr.Height()) / 2;
  608.         fr.bottom = fr.top + tr.Height();
  609.       }
  610.  
  611.       DrawText( memdc, caption, -1, &fr, DT_CENTER | DT_SINGLELINE | DT_VCENTER );
  612.  
  613.       fr.Inflate( 2, 2 );
  614.  
  615.       if( fooData->State != bsUp )
  616.       {
  617.         SelectBrush( memdc, nullBrush );
  618.         SelectPen( memdc, dkGrayDashPen );
  619.         Rectangle( memdc, fr.left, fr.top, fr.right, fr.bottom );
  620.       }
  621.     }
  622.  
  623.     BitBlt( hdc, 0, 0, cr.right, cr.bottom, memdc, 0, 0, SRCCOPY );
  624.  
  625.     RestoreDC( memdc, save );
  626.  
  627.     DeletePen( dkGrayPen );
  628.     DeletePen( ltGrayPen );
  629.     DeletePen( dkGrayDashPen );
  630.     DeleteBitmap( bitmap );
  631.  
  632.     DeleteDC( memdc );
  633.     EndPaint( hwnd, &ps );
  634.   }
  635. }
  636.  
  637. void EvFooBtnSetFont( HWND hwnd, HFONT hfont, BOOL fRedraw )
  638. {
  639.   FooBtnData *fooData = GetFooButtonData( hwnd );
  640.  
  641.   if( fooData )
  642.   {
  643.     fooData->Font = hfont;
  644.     if( fRedraw )
  645.       InvalidateRect( hwnd, 0, FALSE );
  646.   }
  647. }
  648.  
  649. HFONT EvFooBtnGetFont( HWND hwnd )
  650. {
  651.   FooBtnData *fooData = GetFooButtonData( hwnd );
  652.   HFONT result = 0;
  653.  
  654.   if( fooData )
  655.     result = fooData->Font;
  656.  
  657.   return result;
  658. }
  659.